#include "lib.h"

#include "bjhand.h"
#include "bjconn.h"
#include "cardmgr.h"
#include "bjrules.h"

#define SELF	BJHand
#define SUPER	Hand

BJHand::BJHand
(
	CardMgr*	pMgr,
	bool8		isHardAces
)
:	Hand(pMgr)
{
	m_actionBits			= BJF_NORMAL;
	m_cardFaceBits			= 0;
	m_nBets					= 0;
	m_nHand					= 0;
	m_payout				= 0;
	m_bonus					= 0;
	m_bonusName[0]			= 0;
	m_isHardAces			= isHardAces;
	m_bonusBalanceBet		= 0;
	m_updateBalance			= true;	// this flag must be released after the balance update !!
}

BJHand::~BJHand()
{

}

int32
BJHand::GetScoreHard()
{
	int scoreHard = 0;
	int nCards = getCount();
	for (int i=0; i < nCards; i++)
	{
		uint8 card	= getCardAt(i);
		int32 value = BJRules::CardValue( card );
		scoreHard += value;
	}
	return scoreHard;
}

int32
BJHand::GetScoreHardVisible()
{
	int scoreHard = 0;
	int nCards = getCount();
	for (int i=0; i < nCards; i++)
	if (IsCardVisible(i))
	{
		uint8 card	= getCardAt(i);
		int32 value = BJRules::CardValue( card );
		scoreHard += value;
	}
	return scoreHard;
}

bool8
BJHand::IsHardAces()
{
	return m_isHardAces;
}

bool8
BJHand::IsSoftAces()
{
	return !IsHardAces();
}

bool8
BJHand::IsSoft()
{
	if (IsSoftAces())
	if (GetNAces() > 0)
	if (GetScoreHard() <= 11)
		return true;
	return false;
}

bool8
BJHand::IsAce( uint8 card )
{
	int isAce = (mgr->getRank( card ) == CardMgr::ACE);
	return isAce;
}

int32
BJHand::GetNAces()
{
	int nAces	= 0;
	int nCards	= getCount();
	for (int i=0; i < nCards; i++)
	{
		uint8 card = getCardAt(i);
		if (IsAce( card ))
			nAces++;
	}
	return nAces;
}

int32
BJHand::GetNAcesVisible()
{
	int nAces	= 0;
	int nCards	= getCount();
	for (int i=0; i < nCards; i++)
	if (IsCardVisible(i))
	{
		uint8 card = getCardAt(i);
		if (card == CardMgr::ACE)
			nAces++;
	}
	return nAces;
}

int32
BJHand::GetScore()
{
	int32 score = GetScoreHard();

	if (IsSoftAces())
	if (GetNAces() > 0)
	if (score <= 11)
		score += 10;

	return score;
}

int32
BJHand::GetScoreVisible()
{
	int32 score = GetScoreHardVisible();

	if (IsSoftAces())
	if (GetNAcesVisible() > 0)
	if (score <= 11)
		score += 10;

	return score;
}

bool8
BJHand::IsNatural()
{
	int nDealerCards = IsSoftAces() ? 2 : 3;

	if (!wasAction(BJF_SPLIT))
	if (getCount() == nDealerCards)
	if (GetScore() == 21)
		return true;

	return false;
}

bool8
BJHand::IsAceShowing()
{
	int nCards = getCount();
	for (int i=0; i<nCards; i++)
	if (IsCardVisible(i))
	if (mgr->getRank(cards[i]) == CardMgr::ACE)
		return true;
	return false;

}

BJHand*
BJHand::HandleSplit()
{
	int isHardAces = IsHardAces();
	BJHand* nextHand = new BJHand(mgr,isHardAces);
	if (!nextHand)
		return (BJHand*)0;

	setAction(BJF_SPLIT);
	nextHand->setAction(BJF_SPLIT);

	nextHand->add(cards[0]);
	cards[0] = cards[1];
	--count;

	nextHand->next = next;
	next = nextHand;

	nextHand->m_nBets		= m_nBets;
//	nextHand->m_actionBits	= m_actionBits;

	return nextHand;
}

/// [2013-07-10] Charles. Added for supporting 'Zappit Rackcard'.
void BJHand::HandleZap()
{
	// make current hand empty
	count = 0;
}

void
BJHand::restore
(
	uint8* cards,
	int32 count,
	uint8 nBets,
	uint8 actionBits,
	int32 bonusBalanceBet,
	BJHand* prev
)
{
	SUPER::restore(cards, count);

	m_actionBits	= actionBits;
	m_nBets			= nBets;
	m_bonusBalanceBet = bonusBalanceBet;

	if (prev)
	{
		prev->next = this;
	}

	RestoreCardFacingBits();
}

bool8
BJHand::add(uint8 Card, bool8 down )
{
	bool8 bResult = Hand::add(Card);

	int nCards = getCount();

	SetCardVisible( nCards-1, down==0 );

	return bResult;
}

/*
	These two routines are used by the tracker routines
	before storing a hand in a saved game
	the database must remember the facing of each card
	if bit 7 in the card byte is set then the player does not
	yet possess knowledge of that card
*/
void
BJHand::SetCardFacingBits()
{
	int nCards = getCount();
	uint8* pCards = getCards();

	for (int i=0; i<nCards; i++)
	if (IsCardVisible(i))
		pCards[i] &= 0x7f;	//clear bit 7
	else
		pCards[i] |= 0x80;	//set bit 7
}

void
BJHand::ClrCardFacingBits()
{
	int nCards = getCount();
	uint8* pCards = getCards();

	for (int i=0; i<nCards; i++)
		pCards[i] &= 0x7f;	//clear bit 7
}

int
BJHand::IsCardVisible( int nCard )
{
	int isVis = ((m_cardFaceBits & (1<<nCard)) == 0);
	return isVis;
}

void
BJHand::SetCardVisible( int nCard, int vis )
{
	//0=face up, 1=face dn
	if (vis)
		m_cardFaceBits &= (~(1<<(nCard)));	//0=face up
	else
		m_cardFaceBits |= (1<<(nCard));		//1=face dn
}

void
BJHand::RestoreCardFacingBits()
{
	m_cardFaceBits = 0;
	int nCards = getCount();
	uint8* pCards = getCards();

	for (int i=0; i<nCards; i++)
	{
		if (pCards[i] & 0x80)	//facing bit
		{
			pCards[i] &= 0x7f;	//turn it off
			m_cardFaceBits |= (1<<i);
		}
	}
}

int32
BJHand::GetNCardsVisible()
{
	int32 nCards=getCount();
	int32 nCardsVisible = nCards;
	for (int i=0; i<nCards; i++)
	if (m_cardFaceBits & (1<<i))
		nCardsVisible--;
	return nCardsVisible;
}

void
BJHand::RevealAllCards()
{
	//make all cards to be visible to the player
	m_cardFaceBits = 0;
}

void
BJHand::sendCard( int32 i, BJConnection* conn )
{
	uint8*	pCards	= getCards();
	uint8	card	= pCards[i];
	if (!IsCardVisible(i))
		card = 0;
	conn->SENDBYTE(card);
}

void
BJHand::sendLastCard( BJConnection* conn )
{
	uint8 nCards	= (uint8)getCount();
	sendCard( nCards-1, conn );
}

void
BJHand::sendCards( BJConnection* conn )
{
	uint8 nCards	= (uint8)getCount();
	conn->SENDBYTE(nCards);

	for (int i=0; i<nCards; i++)
		sendCard( i, conn );
}

void
BJHand::send( BJConnection* conn )
{
	uint8	nBets		= GetNBets();
	uint8	actions		= (uint8)GetActions();
	uint8	score		= (uint8)GetScoreVisible();

	conn->SENDBYTE(nBets);
	conn->SENDBYTE(actions);
	conn->SENDBYTE(score);
	sendCards(conn);
}
